package org.springblade.tms.module.car.importer;

import cn.hutool.core.collection.ListUtil;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springblade.common.utils.EnumUtils;
import org.springblade.common.utils.StreamUtils;
import org.springblade.core.excel.support.ExcelImporter;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.tms.global.enums.CarType;
import org.springblade.tms.global.enums.CargoTypeEnum;
import org.springblade.tms.module.car.base.CarManagementService;
import org.springblade.tms.module.car.dto.CarDto;
import org.springblade.tms.module.car.vo.CarExcelVO;
import org.springblade.tms.module.userinfo.entity.TMUserInfo;
import org.springframework.data.redis.core.RedisTemplate;

import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @projectName: BladeX
 * @package: org.springblade.tms.module.supercargoinfo.Importer
 * @className: EscortManagementImporter
 * @author: yr
 * @description: 押运员数据导入类
 * @date: 2022/4/22 16:13
 */
@RequiredArgsConstructor
public class CarImporter implements ExcelImporter<CarExcelVO> {
	//服务
	private final CarManagementService service;
	//线程
	private final ThreadPoolExecutor executor;
	//验证器
	private final Validator validator;
	//当前用户
	private final TMUserInfo tMuserInfo;
	//reidsKey
	private final String ImportNo;

	private final RedisTemplate redisTemplate;


	@Override
	@SneakyThrows
	public void save(List<CarExcelVO> data) {
		BladeUser user = AuthUtil.getUser();
		//验证器验证
		List<CarExcelVO> failure = new ArrayList<>();
		data.forEach(carExcelVO -> {
			Set<ConstraintViolation<CarExcelVO>> validate;
			if (carExcelVO.getCarType().equals(CarType.VEHICLE.description())) {
				validate = validator.validate(carExcelVO, CarExcelVO.vehicle.class);
			} else if (carExcelVO.getCarType().equals(CarType.TRAILER.description())) {
				validate = validator.validate(carExcelVO, CarExcelVO.trailer.class);
			} else {
				validate = validator.validate(carExcelVO, CarExcelVO.tractor.class);
			}
			if (validate != null && !validate.isEmpty()) {
				failure.add(carExcelVO);
			}
		});
		//失败条数放入redis
		data.removeAll(failure);
		AtomicLong count = new AtomicLong(failure.size());
		//每500条数据开一个线程
		List<CarDto> tmCars = new ArrayList<>();
		data.forEach(carExcelVO -> {
			//时间类型转换
			CarDto carDto = BeanUtil.copy(carExcelVO, CarDto.class);
			assert carDto != null;
			if (carExcelVO.getCertificationBindCarCheckValidStart()!=null) {
				carDto.setCertificationBindCarCheckValidStart(LocalDateTime
					.ofInstant(carExcelVO.getCertificationBindCarCheckValidStart().toInstant(), ZoneId.systemDefault()));
			}
			if (carExcelVO.getCertificationBindCarCheckValidEnd()!=null) {
				carDto.setCertificationBindCarCheckValidEnd(LocalDateTime
					.ofInstant(carExcelVO.getCertificationBindCarCheckValidEnd().toInstant(), ZoneId.systemDefault()));
			}
			if (carExcelVO.getCertificationCarCheckValidEnd()!=null) {
				carDto.setCertificationCarCheckValidEnd(LocalDateTime
					.ofInstant(carExcelVO.getCertificationCarCheckValidEnd().toInstant(), ZoneId.systemDefault()));
			}

			if (carExcelVO.getCertificationCarCheckValidStart()!=null) {
				carDto.setCertificationCarCheckValidStart(LocalDateTime
					.ofInstant(carExcelVO.getCertificationCarCheckValidStart().toInstant(), ZoneId.systemDefault()));
			}
			if (carExcelVO.getCertificationCarWorkValidStart()!=null) {
				carDto.setCertificationCarWorkValidStart(LocalDateTime
					.ofInstant(carExcelVO.getCertificationCarWorkValidStart().toInstant(), ZoneId.systemDefault()));
			}
			if (carExcelVO.getCertificationCarWorkValidEnd()!=null) {
				carDto.setCertificationCarWorkValidEnd(LocalDateTime
					.ofInstant(carExcelVO.getCertificationCarWorkValidEnd().toInstant(), ZoneId.systemDefault()));
			}
			if (carExcelVO.getCertificationBindCarWorkValidStart()!=null) {
				carDto.setCertificationBindCarWorkValidStart(LocalDateTime
					.ofInstant(carExcelVO.getCertificationBindCarWorkValidStart().toInstant(), ZoneId.systemDefault()));
			}
			if (carExcelVO.getCertificationBindCarWorkValidEnd()!=null) {
				carDto.setCertificationBindCarWorkValidEnd(LocalDateTime
					.ofInstant(carExcelVO.getCertificationBindCarWorkValidEnd().toInstant(), ZoneId.systemDefault()));
			}

			if (carExcelVO.getContainerReportValidStart()!=null) {
				carDto.setContainerReportValidStart(LocalDateTime
					.ofInstant(carExcelVO.getContainerReportValidStart().toInstant(), ZoneId.systemDefault()));
			}
			if (carExcelVO.getContainerReportValidEnd()!=null) {
				carDto.setContainerReportValidEnd(LocalDateTime
					.ofInstant(carExcelVO.getContainerReportValidEnd().toInstant(), ZoneId.systemDefault()));
			}
			if (carExcelVO.getVehicleInsuranceValidStart()!=null) {
				carDto.setVehicleInsuranceValidStart(LocalDateTime
					.ofInstant(carExcelVO.getVehicleInsuranceValidStart().toInstant(), ZoneId.systemDefault()));
			}
			if (carExcelVO.getVehicleInsuranceValidEnd()!=null) {
				carDto.setVehicleInsuranceValidEnd(LocalDateTime
					.ofInstant(carExcelVO.getVehicleInsuranceValidEnd().toInstant(), ZoneId.systemDefault()));
			}
			if (carExcelVO.getCertificateTankTruckStart()!=null) {
				carDto.setCertificateTankTruckStart(LocalDateTime
					.ofInstant(carExcelVO.getCertificateTankTruckStart().toInstant(), ZoneId.systemDefault()));
			}
			if (carExcelVO.getCertificateTankTruckEnd()!=null) {
				carDto.setCertificateTankTruckEnd(LocalDateTime
					.ofInstant(carExcelVO.getCertificateTankTruckEnd().toInstant(), ZoneId.systemDefault()));
			}
			tmCars.add(carDto);
		});
		List<List<CarDto>> split = ListUtil.split(tmCars, 500);
		List<CompletableFuture<Void>> taskList = new ArrayList<>();
		split.forEach(list -> taskList.add(
			CompletableFuture.supplyAsync(() -> {
				list.forEach(car -> {
					try {
						car.setCarType(EnumUtils.getEnumByDesc(CarType.class,car.getCarType()).get().value());
						car.setTransportGoodsType(EnumUtils.getEnumByDesc(CargoTypeEnum.class,car.getTransportGoodsType()).get().value());
						R save = service.save(car, tMuserInfo,user);
						if (!save.isSuccess()){
							count.getAndIncrement();
						}
					}catch (Throwable e){
						count.getAndIncrement();
					}
				});
				return null;
			}, executor)
		));
		taskList.forEach(StreamUtils.ofConsumer(voidCompletableFuture -> voidCompletableFuture.get()));
		redisTemplate.opsForValue().set(ImportNo, count.longValue());
	}
}
